package org.springblade.modules.admin.service.erp.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.admin.dto.erp.*;
import org.springblade.modules.admin.service.erp.IPartnerCloudSpaceTableService;
import org.springblade.modules.admin.utils.FeiShuUtils;
import org.springblade.modules.admin.vo.erp.tables.PartnerCloudTableItemListVO;
import org.springblade.modules.admin.vo.erp.tables.PartnerCloudTableItemVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * @author Sharry
 * @since 2024-12-24
 */
@Service
@Slf4j
public class PartnerCloudSpaceTableServiceImpl implements IPartnerCloudSpaceTableService {

	@Value("${erp.api_key}")
	private String apiKey;

	@Value("${erp.prefix_url}")
	private String prefixUrl;

	private final Integer SUCCESS_CODE = 0;

	private final String CODE_KEY = "code";

	private final String REQUEST_HEADER_NAME = "Open-Authorization";

	private final int BATCH_MAX_SIZE = 100;

	@Override
	public PartnerCloudTableItemListVO searchTable(PartnerCloudTableSearchFullDTO searchFullDTO) {
		// 1. 发起请求
		String requestUrl = prefixUrl + "/item/list";
		String bodyJsonString = JSONObject.toJSONString(searchFullDTO);
		String requestResult = postRequest(requestUrl, bodyJsonString);
		log.info("伙伴云批量查询请求参数:{}", searchFullDTO);
		// 2. 解析结果
		JSONObject resultJsonObject = JSONObject.parseObject(requestResult, JSONObject.class);
		log.info("伙伴云批量查询请求结果:{}", resultJsonObject);
		JSONObject resultData = this.validateResultAndGetData(resultJsonObject);
		String itemName = "items";
		if(!resultData.containsKey(itemName)){
			log.error("伙伴云批量查询请求结果返回数据格式不正确:{}", resultJsonObject);
			throw new ServiceException("伙伴云批量查询请求结果返回数据格式不正确");
		}
		return JSONObject.parseObject(resultData.toJSONString(), PartnerCloudTableItemListVO.class);
	}

	@Override
	public PartnerCloudTableItemListVO searchFullTable(PartnerCloudTableSearchFullDTO searchFullDTO) {
		// 0. 结果准备
		PartnerCloudTableItemListVO resultVO = new PartnerCloudTableItemListVO();
		List<PartnerCloudTableItemVO> resultItems = new ArrayList<>();
		int limit = BATCH_MAX_SIZE;
		// 1. 从 offset = 0 开始，每次请求 100 条数据，直到查询完毕
		int offset = 0;
		searchFullDTO.setLimit(limit);
		searchFullDTO.setOffset(offset);
		PartnerCloudTableItemListVO requestVO = this.searchTable(searchFullDTO);
		if(requestVO.getItems().size() < limit){
			resultItems.addAll(requestVO.getItems());
			resultVO.setItems(resultItems);
			return resultVO;
		}
		resultItems.addAll(requestVO.getItems());
		// 2. 循环请求，直到查询完毕
		while (requestVO.getItems().size() >= limit) {
			offset += limit;
			searchFullDTO.setOffset(offset);
			requestVO = this.searchTable(searchFullDTO);
			resultItems.addAll(requestVO.getItems());
		}
		resultVO.setItems(resultItems);
		return resultVO;
	}

	@Override
	public PartnerCloudTableItemListVO searchTableByCondition(PartnerCloudTableFilterDTO filterDTO) {
		// 1. 发起请求
		String requestUrl = prefixUrl + "/item/list";
		filterDTO.setLimit(BATCH_MAX_SIZE);
		int offset = 0;
		filterDTO.setOffset(offset);
		String bodyJsonString = JSONObject.toJSONString(filterDTO);
		String requestResult = postRequest(requestUrl, bodyJsonString);
		log.info("伙伴云批量查询请求参数:{}", filterDTO);
		// 2. 解析结果
		JSONObject resultJsonObject = JSONObject.parseObject(requestResult, JSONObject.class);
		log.info("伙伴云批量查询请求结果:{}", resultJsonObject);
		JSONObject resultData = this.validateResultAndGetData(resultJsonObject);
		String itemName = "items";
		if(!resultData.containsKey(itemName)){
			log.error("伙伴云批量查询请求结果返回数据格式不正确:{}", resultJsonObject);
			throw new ServiceException("伙伴云批量查询请求结果返回数据格式不正确");
		}
		return JSONObject.parseObject(resultData.toJSONString(), PartnerCloudTableItemListVO.class);
	}

	@Override
	public PartnerCloudTableItemVO getTableItem(String itemId) {
		if(Func.isNull(itemId)){
			throw new ServiceException("伙伴云获取item详情参数错误：itemId不能为空");
		}
		log.info("伙伴云获取item详情请求参数:{}", itemId);
		String requestUrl = prefixUrl + "/item" + "/" + itemId;
		String requestResult = postRequest(requestUrl, null);
		JSONObject resultJsonObject = JSONObject.parseObject(requestResult, JSONObject.class);
		log.info("伙伴云获取item详情请求结果:{}", resultJsonObject);
		JSONObject dataResult = validateResultAndGetData(resultJsonObject);
		String itemName = "item";
		JSONObject itemResult = validateKeyAndGetKeyValues(dataResult, itemName);
		return JSONObject.parseObject(itemResult.toJSONString(), PartnerCloudTableItemVO.class);
	}

	@Override
	public boolean deleteTableItemsBatch(PartnerCloudTableDeleteBatchDTO deleteBatchDTO) {
		String requestUrl = prefixUrl + "/items";
		String bodyJsonString = JSONObject.toJSONString(deleteBatchDTO);
		// 每次请求 100 条数据
		List<String> itemIds = deleteBatchDTO.getItem_ids();
		List<List<String>> splitList = ListUtil.split(itemIds, BATCH_MAX_SIZE);
		boolean isSuccess = true;
		for (List<String> tempBatchList : splitList) {
			PartnerCloudTableDeleteBatchDTO tempDeleteBatchDTO = new PartnerCloudTableDeleteBatchDTO();
			BeanUtils.copyProperties(deleteBatchDTO, tempDeleteBatchDTO);
			tempDeleteBatchDTO.setItem_ids(tempBatchList);
			String bodyJsonStringTemp = JSONObject.toJSONString(tempDeleteBatchDTO);
			String result = deleteRequest(requestUrl, bodyJsonStringTemp);
			isSuccess &= getResultCode(JSONObject.parseObject(result)).equals(SUCCESS_CODE);
		}
		return isSuccess;
	}

	@Override
	public boolean saveOrUpdateByFields(PartnerCloudTableSaveOrUpdateDTO saveOrUpdateDTO) {
		boolean isSuccess = true;
		if (Func.isEmpty(saveOrUpdateDTO.getItems())) {
			return true;
		}
		// 设置模式
		String requestUrl = prefixUrl + "/items";
		String updateType = "upsert";
		saveOrUpdateDTO.setUpdate_type(updateType);

		// 切分请求
		List<PartnerCloudTableItemDTO> items = saveOrUpdateDTO.getItems();
		List<List<PartnerCloudTableItemDTO>> splitList = ListUtil.split(items, BATCH_MAX_SIZE);
		for (List<PartnerCloudTableItemDTO> tempBatchList : splitList) {
			PartnerCloudTableSaveOrUpdateDTO tempSaveOrUpdateDTO = new PartnerCloudTableSaveOrUpdateDTO();
			BeanUtils.copyProperties(saveOrUpdateDTO, tempSaveOrUpdateDTO);
			tempSaveOrUpdateDTO.setItems(tempBatchList);
			String bodyJsonString = JSONObject.toJSONString(tempSaveOrUpdateDTO);
			String result = putRequest(requestUrl, bodyJsonString);
			isSuccess &= getResultCode(JSONObject.parseObject(result)).equals(SUCCESS_CODE);
		}
		return isSuccess;
	}

	@Override
	public String uploadFile(File file) {
		String requestUrl = prefixUrl + "/file/upload";
		String result = uploadFile(requestUrl, file);
		JSONObject jsonResult = JSONObject.parseObject(result);
		if(getResultCode(jsonResult).equals(SUCCESS_CODE)){
			JSONObject targetResult = validateResultAndGetData(jsonResult);
			return validateKeyAndGetKeyValueString(targetResult, "file_id");
		}
		return null;
	}

	/**
	 * 组装 Open-Authorization 头部方法
	 *
	 * @return Open-Authorization 头部
	 */
	private String getOpenAuthorization() {
		return "Bearer " + apiKey;
	}

	/**
	 * Post 请求方法
	 */
	private String postRequest(String requestUrl, String bodyJsonString) {
		return HttpRequest.post(requestUrl)
			.header(REQUEST_HEADER_NAME, this.getOpenAuthorization())
			.header("Content-Type", "application/json;charset=UTF-8")
			.body(bodyJsonString)
			.execute()
			.body();
	}

	/**
	 * Delete 请求方法
	 */
	private String deleteRequest(String requestUrl, String bodyJsonString) {
		return HttpRequest.delete(requestUrl)
			.header(REQUEST_HEADER_NAME, this.getOpenAuthorization())
			.header("Content-Type", "application/json;charset=UTF-8")
			.body(bodyJsonString)
			.execute()
			.body();
	}

	/**
	 * Put 请求方法
	 */
	private String putRequest(String requestUrl, String bodyJsonString) {
		return HttpRequest.put(requestUrl)
			.header(REQUEST_HEADER_NAME, this.getOpenAuthorization())
			.header("Content-Type", "application/json;charset=UTF-8")
			.body(bodyJsonString)
			.execute()
			.body();
	}

	/**
	 * 上传文件
	 */
	private String uploadFile(String requestUrl, File file) {
		return HttpRequest.post(requestUrl)
			.header(REQUEST_HEADER_NAME, this.getOpenAuthorization())
			.form("type", "attachment")
			.form("name", file.getName())
			.form("source", file)
			.execute()
			.body();
	}

	/**
	 * 伙伴云请求返回结果是否成功验证方法
	 */
	private JSONObject validateResultAndGetData(JSONObject resultObject) {
		if (Func.isNull(resultObject)) {
			log.error("伙伴云请求返回结果为空");
			throw new ServiceException("伙伴云请求返回结果为空");
		}
		Set<String> keySet = resultObject.keySet();
		String dataKey = "data";
		if (!keySet.contains(CODE_KEY) || !keySet.contains(dataKey)) {
			log.error("伙伴云批量查询请求结果返回数据格式不正确:{}", resultObject);
			throw new ServiceException("伙伴云批量查询请求结果返回数据格式不正确");
		}
		if (!SUCCESS_CODE.equals(resultObject.getInteger(CODE_KEY))) {
			log.error("伙伴云批量查询请求失败:{}", resultObject);
			throw new ServiceException("伙伴云批量查询请求失败");
		}
		return resultObject.getJSONObject(dataKey);
	}

	/**
	 * 获取结果code
	 */
	private Integer getResultCode(JSONObject resultObject) {
		if (Func.isNull(resultObject)) {
			log.error("伙伴云请求返回结果为空");
			throw new ServiceException("伙伴云请求返回结果为空");
		}
		Set<String> keySet = resultObject.keySet();
		if (!keySet.contains(CODE_KEY)) {
			log.error("伙伴云批量查询请求结果返回数据格式不为正确预期:{}", resultObject);
			throw new ServiceException("伙伴云批量查询请求结果返回数据格式不为正确预期");
		}
		return resultObject.getInteger(CODE_KEY);
	}

	/**
	 * 验证结果是否包含指定key，并返回key对应的值
	 */
	private JSONObject validateKeyAndGetKeyValues(JSONObject resultObject, String key) {
		if (Func.isNull(resultObject)) {
			log.error("伙伴云请求返回结果为空");
			throw new ServiceException("伙伴云请求返回结果为空");
		}
		Set<String> keySet = resultObject.keySet();
		if (!keySet.contains(key)) {
			log.error("伙伴云批量查询请求结果返回数据格式不正确:{}", resultObject);
			throw new ServiceException("伙伴云批量查询请求结果返回数据格式不正确");
		}
		return resultObject.getJSONObject(key);
	}

	private String validateKeyAndGetKeyValueString(JSONObject resultObject, String key) {
		if (Func.isNull(resultObject)) {
			log.error("伙伴云请求返回结果为空");
			throw new ServiceException("伙伴云请求返回结果为空");
		}
		Set<String> keySet = resultObject.keySet();
		if (!keySet.contains(key)) {
			log.error("伙伴云批量查询请求结果返回数据格式不正确:{}", resultObject);
			throw new ServiceException("伙伴云批量查询请求结果返回数据格式不正确");
		}
		return resultObject.getString(key);
	}
}
